﻿using System;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using ADEVSO.Util;
using SmartParking.Bussiness;
using SmartParking.Data.Entities;

namespace SmartParking.Web.Models
{
    public class ReservationsModel
    {
        private HttpContextBase _httpContext = null;

        public ReservationModel Reservation;
        //public ReservationListModel Reservations;
        public string ErrorMessage;
        public string ReservationsHtml;
                
        public ReservationsModel(HttpContextBase httpContext)
        {
            _httpContext = httpContext;
            Reservation = new ReservationModel();
            RefreshReservations();
            //Reservations = new ReservationListModel(httpContext);
        }

        public bool HasError { get { return !String.IsNullOrEmpty(ErrorMessage); } }

        public List<ReservationListItemModel> Reservations { get; private set; }

        public void RefreshReservations()
        {
            Reservations = new List<ReservationListItemModel>();
            var liveReservations = ReservationsManager.GetLiveReservations(_httpContext.ApplicationInstance.Application, _httpContext.Session);
            Reservations.AddRange(liveReservations.Select(item => ReservationListModel.CopyReservationData(item)));
        }
    }

    public class ReservationModel
    {
        [Required]
        [Display(Name = "Parqueo")]
        public int ParkingId { get; set; }

        [Required]
        [Display(Name = "Zona")]
        public int ParkingZoneId { get; set; }

        [Display(Name = "Precio")]
        public decimal PriceHour { get; set; }

        [Display(Name = "Comisión")]
        public decimal Commission { get; set; }

        [Required]
        [Display(Name = "Fecha")]
        public string Date { get; set; }

        [Required]
        [Display(Name = "Entrada")]
        public int StartHour { get; set; }

        [Required]
        [Display(Name = "Salida")]
        public int EndHour { get; set; }

        [Required]
        [StringLength(10)]
        [Display(Name = "Placa")]
        public string CarPlate { get; set; }

        public List<SelectListItem> Parkings { get; set; }
        public List<SelectListItem> ParkingZones { get; set; }
        public List<SelectListItem> OpenHours { get; set; }
        public List<SelectListItem> CloseHours { get; set; }

        public ReservationModel()
        {
            Refresh();
        }

        /// <summary>
        /// Return an order detail from a model
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static OrderDetail CreateOrderDetail(ReservationModel model)
        {
            var reservation = new OrderDetail();
            reservation.ParkingID = model.ParkingId;
            reservation.ParkingZoneID = model.ParkingZoneId;
            var date = Convert.ToDateTime(model.Date, new CultureInfo("es-CR"));
            var hour = ((Hour)model.StartHour);
            var time = new TimeSpan(hour.GetHour(), hour.GetMinutes(), 0);
            reservation.ReservationStartDateTime = date.Add(time);
            hour = ((Hour)model.EndHour);
            time = new TimeSpan(hour.GetHour(), hour.GetMinutes(), 0);
            reservation.ReservationEndDateTime = date.Add(time);
            reservation.CarPlate = model.CarPlate;
            return reservation;
        }

        /// <summary>
        /// Refresh model
        /// </summary>
        public void Refresh()
        {
            RefreshParkings();
            RefreshParkingZones();
            RefreshPriceHourAndCommission();
            RefreshOpenHours();
            RefreshCloseHours();
        }

        private void RefreshParkings()
        {
            var items = new List<SelectListItem>();
            items.Add(new SelectListItem() { Text = "Seleccione un parqueo...", Value = "0", Selected = ParkingId == 0 }); //Add empty item
            if (ParkingId == 0)
            {
                var parkings = ParkingManager.GetParkingsToWebReservations();
                items.AddRange(parkings.Select(p => new SelectListItem() {Text = p.Name.Trim(), Value = Convert.ToString(p.ParkingID).Trim(), Selected = p.ParkingID == ParkingId}));
                ParkingZoneId = 0;
            }
            Parkings = items;
        }

        private void RefreshParkingZones()
        {
            var items = new List<SelectListItem>();
            if (ParkingId != 0)
            {
                items.Add(new SelectListItem() { Text = "Seleccione una zona de parqueo...", Value = "0", Selected = ParkingZoneId == 0 }); //Add empty item
                if (ParkingZoneId == 0)
                {
                    var parkingZones = ParkingManager.GetParkingZonesToWebReservations(ParkingId);
                    items.AddRange(parkingZones.Select(p => new SelectListItem() {Text = p.Name.Trim(), Value = Convert.ToString(p.ParkingZoneID).Trim(), Selected = ParkingZoneId == p.ParkingZoneID}));
                    StartHour = 0;
                }
            }
            ParkingZones = items;
        }

        private void RefreshPriceHourAndCommission()
        {
            if (ParkingId != 0 && ParkingZoneId != 0)
            {                
                var parkingZoneFare = ParkingManager.GetParkingZoneWebFare(ParkingZoneId);
                PriceHour = parkingZoneFare.PriceHour;
                Commission = parkingZoneFare.ParkingZone.WebCommisionAmount;
            }
        }

        private void RefreshOpenHours()
        {
            var items = new List<SelectListItem>();
            if (ParkingId != 0 && ParkingZoneId != 0)
            {                
                items.Add(new SelectListItem() { Text = "Seleccione una hora de entrada...", Value = "0", Selected = StartHour == 0 }); //Add empty item
                if ((Hour)StartHour == Hour.None)
                {
                    var parkingZone = ParkingManager.GetParkingZone(ParkingZoneId);
                    var hours = Hour.AM0100.RangeHours(parkingZone.OpenHour.ToHour(), parkingZone.CloseHour.ToHour(), parkingZone.AllowHalfHour);
                    items.AddRange(hours.Select(h => new SelectListItem() {Text = h.ToStringHour(), Value = Convert.ToString(Convert.ToInt32(h)), Selected = (Hour) StartHour == h}));
                    EndHour = 0;
                }                
            }
            OpenHours = items;
        }

        private void RefreshCloseHours()
        {
            var items = new List<SelectListItem>();
            if (ParkingId != 0 && ParkingZoneId != 0 && (Hour)StartHour != Hour.None)
            {                
                items.Add(new SelectListItem() { Text = "Seleccione una hora de salida...", Value = "0", Selected = EndHour == 0 }); //Add empty item
                if ((Hour)StartHour != Hour.None && (Hour)EndHour == Hour.None)
                {
                    var parkingZone = ParkingManager.GetParkingZone(ParkingZoneId);
                    var hours = Hour.AM0100.RangeHours((Hour)StartHour + 1, parkingZone.CloseHour.ToHour(), parkingZone.AllowHalfHour);
                    items.AddRange(hours.Select(h => new SelectListItem() {Text = h.ToStringHour(), Value = Convert.ToString(Convert.ToInt32(h)), Selected = (Hour) EndHour == h}));
                }                
            }
            CloseHours = items;
        }
    }

    public class ReservationListItemModel
    {
        public string Id { get; set; }
        public string Group { get; set; }
        public string ParkingName { get; set; }
        public string ParkingZoneName { get; set; }
        public string Date { get; set; }
        public string ReservationStartHour { get; set; }
        public string ReservationEndHour { get; set; }
        public string StartHour { get; set; }
        public string EndHour { get; set; }
        public string CarPlate { get; set; }
        public string Amount { get; set; }
        public string Comission { get; set; }
    }

    public class ReservationListModel
    {
        private readonly HttpContextBase _httpContext = null;
        public string ViewTitle { get; private set; }
        public string ItemDeleteView { get; private set; }
        public string ListTitle { get; private set; }
        public List<ReservationListItemModel> Reservations { get; private set; }
        public bool ReadOnly { get; private set; }
        public string EmptyMessage { get; private set; }

        public ReservationListModel(HttpContextBase httpContext, ReservationListType listType, bool readOnly = false, string orderId = "")
        {
            _httpContext = httpContext;
            ReadOnly = readOnly;
            switch (listType)
            {
                case ReservationListType.Order:
                    {
                        ViewTitle = "Detalle de la Orden";
                        Reservations =
                            ReservationsManager.GetOrderReservations(orderId)
                                               .Select(item => CopyReservationData(item)).ToList();
                        ListTitle = String.Format("Orden #{0} ¢{1}", orderId, Reservations.Sum(item => Convert.ToDecimal(item.Amount) + Convert.ToDecimal(item.Comission)));
                        EmptyMessage = "No hay reservaciones en la orden";
                        ReadOnly = true;
                        break;
                    }
                case ReservationListType.Session:
                    {
                        ViewTitle = "Reservaciones";
                        ItemDeleteView = "DeleteReservation";
                        var id = 0;
                        Reservations =
                            ReservationsManager.GetLiveReservations(_httpContext.ApplicationInstance.Application, _httpContext.Session)
                                               .Select(item => CopyReservationData(item, ref id)).ToList();
                        EmptyMessage = "No se han realizado reservaciones";
                        break;
                    }
                case ReservationListType.Global:
                    {
                        ViewTitle = "Reservaciones en Vivo";
                        ItemDeleteView = "DeleteLiveReservation";
                        Reservations = new List<ReservationListItemModel>();
                        var reservations = ReservationsManager.GetGlobalReservations(_httpContext.ApplicationInstance.Application);
                        var id = 0;
                        reservations.ToList().ForEach(item => item.Value.ForEach(item2 => Reservations.Add(CopyReservationData(item2, ref id, item.Key))));
                        ListTitle = String.Format("En Vivo [{0} {1}]", reservations.Keys.Count, reservations.Keys.Count == 1 ? "sesión" : "sesiones");
                        EmptyMessage = "No hay reservaciones en vivo";
                        break;
                    }
                case ReservationListType.Processing:
                    {
                        ViewTitle = "Reservaciones en Proceso";
                        ItemDeleteView = "DeleteProcessingReservation";
                        Reservations = new List<ReservationListItemModel>();
                        var reservations = ReservationsManager.GetGroupedProcessingReservations();
                        reservations.ToList().ForEach(item => item.Value.ForEach(item2 => Reservations.Add(CopyReservationData(item2))));
                        ListTitle = String.Format("En Proceso [{0} {1}]", reservations.Keys.Count, reservations.Keys.Count == 1 ? "sesión" : "sesiones");
                        EmptyMessage = "No hay reservaciones en proceso";
                        break;
                    }
            }
        }

        internal static ReservationListItemModel CopyReservationData(OrderDetail reservation, string group = "")
        {
            var id = 0;
            return CopyReservationData(reservation, ref id, group);
        }

        internal static ReservationListItemModel CopyReservationData(OrderDetail reservation, ref int id, string group = "")
        {
            var result = new ReservationListItemModel
                {
                    Id = String.Format("{0}-{1}", String.IsNullOrEmpty(reservation.OrderID) ? group : reservation.OrderID, reservation.OrderDetailID == 0 ? id++ : reservation.OrderDetailID),
                    Group = group,
                    ParkingName = ParkingManager.GetParking(reservation.ParkingID).Name.Trim(),
                    ParkingZoneName = ParkingManager.GetParkingZone(reservation.ParkingZoneID).Name.Trim(),
                    Date = reservation.ReservationStartDateTime.HasValue ? reservation.ReservationStartDateTime.Value.ToString("dd/MM/yyyy") : reservation.StartDateTime.HasValue ? reservation.StartDateTime.Value.ToString("dd/MM/yyyy") : String.Empty,
                    ReservationStartHour = reservation.ReservationStartDateTime.HasValue ? reservation.ReservationStartDateTime.Value.ToString("hh:mm tt") : String.Empty,
                    ReservationEndHour = reservation.ReservationEndDateTime.HasValue ? reservation.ReservationEndDateTime.Value.ToString("hh:mm tt") : String.Empty,
                    StartHour = reservation.StartDateTime.HasValue ? reservation.StartDateTime.Value.ToString("hh:mm tt") : String.Empty,
                    EndHour = reservation.EndDateTime.HasValue ? reservation.EndDateTime.Value.ToString("hh:mm tt") : String.Empty,
                    CarPlate = reservation.CarPlate.Trim(),
                    Amount = reservation.Amount.ToString(),
                    Comission = reservation.Commission.ToString()
                };
            return result;
        }

        internal static ReservationListItemModel CopyReservationData(ProcessingReservation reservation)
        {
            var result = new ReservationListItemModel
            {
                Id = reservation.ProcessingReservationsID.ToString(),
                Group = reservation.SessionID.Trim(),
                ParkingName = ParkingManager.GetParking(reservation.ParkingID).Name.Trim(),
                ParkingZoneName = ParkingManager.GetParkingZone(reservation.ParkingZoneID).Name.Trim(),
                Date = reservation.ReservationStartDateTime.HasValue ? reservation.ReservationStartDateTime.Value.ToString("dd/MM/yyyy") : reservation.StartDateTime.HasValue ? reservation.StartDateTime.Value.ToString("dd/MM/yyyy") : String.Empty,
                ReservationStartHour = reservation.ReservationStartDateTime.HasValue ? reservation.ReservationStartDateTime.Value.ToString("hh:mm tt") : String.Empty,
                ReservationEndHour = reservation.ReservationEndDateTime.HasValue ? reservation.ReservationEndDateTime.Value.ToString("hh:mm tt") : String.Empty,
                StartHour = reservation.StartDateTime.HasValue ? reservation.StartDateTime.Value.ToString("hh:mm tt") : String.Empty,
                EndHour = reservation.EndDateTime.HasValue ? reservation.EndDateTime.Value.ToString("hh:mm tt") : String.Empty,
                CarPlate = reservation.CarPlate.Trim(),
                Amount = reservation.Amount.ToString(),
                Comission = reservation.Commission.ToString()
            };
            return result;
        }

        public enum ReservationListType
        {
            Order = 0,
            Session = 1,
            Global = 2,
            Processing = 3
        }
    }

    public class ReservationsManagerModel
    {
        public ReservationListModel LiveReservations;
        public ReservationListModel ProcessingReservations;

        public ReservationsManagerModel(HttpContextBase context)
        {
            LiveReservations = new ReservationListModel(context, ReservationListModel.ReservationListType.Global);
            ProcessingReservations = new ReservationListModel(context, ReservationListModel.ReservationListType.Processing);
        }
    }


    public class DashboardReservationModel
    {
        [Required]
        [Display(Name = "Parqueo")]
        public int ParkingId { get; set; }

        [Required]
        [Display(Name = "Zona")]
        public int ParkingZoneId { get; set; }

        [Required]
        [StringLength(10)]
        [Display(Name = "Placa")]
        public string CarPlate { get; set; }

        public List<SelectListItem> Parkings { get; set; }
        public List<SelectListItem> ParkingZones { get; set; }

        public Schedule Schedule { get; set; }

        public DashboardReservationModel(HttpApplicationState application, DateTime? date = null)
        {
            if (!date.HasValue) date = DateTime.Now;
            Schedule = new Schedule(application, 1, date.Value);
        }
    }    
}